﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using NET.Tools;
using Puzzler.Plugin.Interface;
using Puzzler.Plugin.Interface.Attributes;
using Puzzler.XML;

namespace Puzzler.Plugin
{
    public sealed class PluginManager
    {
        private static readonly String PATH = AppDomain.CurrentDomain.BaseDirectory + "\\plugins";

        private static PluginManager instance;
        public static PluginManager Instance { get { return instance ?? (instance = new PluginManager()); } }

        public List<PluginObject> GridDefaultPuzzles { get; private set; }
        public List<PluginObject> GridSpecialPuzzles { get; private set; }
        public List<PluginObject> ImagePuzzles { get; private set; }
        public List<PluginObject> KidsPuzzles { get; private set; }
        public List<PluginObject> AsiaPuzzles { get; private set; }

        public List<PluginObject> AllPuzzles
        {
            get
            {
                List<PluginObject> list = new List<PluginObject>();
                list.AddRange(GridDefaultPuzzles);
                list.AddRange(GridSpecialPuzzles);
                list.AddRange(ImagePuzzles);
                list.AddRange(KidsPuzzles);
                list.AddRange(AsiaPuzzles);

                return list;
            }
        }

        public PluginObject GetPuzzleByType(String typeName)
        {
            foreach (PluginObject pluginObject in AllPuzzles)
            {
                if (pluginObject.PuzzleClass.AssemblyQualifiedName == typeName)
                {
                    return pluginObject;
                }
            }

            return null;
        }

        private PluginManager()
        {
            GridDefaultPuzzles = new List<PluginObject>();
            GridSpecialPuzzles = new List<PluginObject>();
            ImagePuzzles = new List<PluginObject>();
            KidsPuzzles = new List<PluginObject>();
            AsiaPuzzles = new List<PluginObject>();

            if (new DependencyObject().IsDesignMode())
                return;

            IList<Assembly> assemblyList = new List<Assembly>();
            foreach (FileInfo fileInfo in new DirectoryInfo(PATH).GetFiles("*.dll"))
            {
                assemblyList.Add(Assembly.LoadFile(fileInfo.FullName));
            }

            IList<Type> typeList = new List<Type>();
            foreach (Assembly assembly in assemblyList)
            {
                foreach (Type type in assembly.GetTypes())
                {
                    if (typeof(IPuzzlePlugin).IsAssignableFrom(type))
                    {
                        typeList.Add(type);
                    }
                }
            }
            
            foreach (Type type in typeList)
            {
                PuzzleInfo puzzleInfo = PuzzleUtils.GetPuzzleInfo(type);
                XWizard wizard = PuzzleUtils.GetPuzzleWizard(type);
                XRibbonExtension ribbonExtension = PuzzleUtils.GetPuzzleRibbonExtension(type);
                PluginObject pluginObject = new PluginObject(puzzleInfo, type, wizard, ribbonExtension);

                PuzzleCategory puzzleCategory = puzzleInfo.Category;
                switch (puzzleCategory)
                {
                    case PuzzleCategory.GridDefault:
                        GridDefaultPuzzles.Add(pluginObject);
                        break;
                    case PuzzleCategory.GridSpecial:
                        GridSpecialPuzzles.Add(pluginObject);
                        break;
                    case PuzzleCategory.Kids:
                        KidsPuzzles.Add(pluginObject);
                        break;
                    case PuzzleCategory.Image:
                        ImagePuzzles.Add(pluginObject);
                        break;
                    case PuzzleCategory.Asia:
                        AsiaPuzzles.Add(pluginObject);
                        break;
                    default:
                        throw new NotImplementedException(puzzleCategory.ToString());
                }
            }
        }
    }
}
